/**  
 * Copyright (c) 2010 University of Pennsylvania.
 *     All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS
 *  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied.  See the License for the specific language
 *  governing permissions and limitations under the License.
 *
 */
 
uint8_t join_prob(uint8_t jsel, uint8_t window_size, uint8_t multiplicity)
{
  int i, t = 1, t1 = 1, m, m1;

  if (multiplicity == 0)
    return 0;

  for (i = 0; i < window_size; i++)  // compute probability (t-t1)/t of having a join result
  {
    t *= jsel;
    t1 *= (jsel-1);
  }

  m1 = 100*(t-t1)/t;
  m = m1;
  for (i = 2; i <= multiplicity; i++)
    m = 100-(100-m)*(100-m1)/100;

  return m;  
}

uint32_t estimate_hopcost(uint8_t payload_size)   // estimate cost to send a logical packet
{
  uint32_t sum = 0;
  uint8_t length;

  while (payload_size > 0)      // split packet overhead
  {
    length = MIN(payload_size, MAX_GENERICPAYLOAD-1);
    sum += (length+LINK_OVERHEAD+CONFIRM_OVERHEAD+OS_OVERHEAD); 
    payload_size -= length;     // 1 byte group size/index, 2 bytes crc, 1 byte conf. seq + 5 bytes confirm overhead + OS overhead
  }

  return sum;
}

uint32_t estimate_forwardmsgcost(uint8_t no_pathvec, uint8_t is_base, int path_len,
  uint8_t *path_levels, uint8_t pathlevel_reverse, uint8_t payload_size)  // estimate cost to send forwarding msg
{
  int i;
  uint32_t sum = 0;

  for (i = 0; i < path_len; i++)
    sum += no_pathvec ?
      estimate_hopcost(FORWARD_OVERHEAD+payload_size)*(is_base ? CONG_FACTOR(i+1) : CONGFACTOR_BASE) :
      estimate_hopcost(FORWARD_OVERHEAD+PATHVEC_OVERHEAD(path_len-i-1)+payload_size)*
      (path_levels ? CONG_FACTOR(path_levels[pathlevel_reverse ? path_len-i-1 : i]) : CONGFACTOR_BASE);
                 // 4 - cmd, addresses and lengths, 0/i - path vector len, and estimate retransmission
  return sum;
}

uint32_t estimate_singlejoincost(uint8_t is_base, int path_len, uint8_t *path_levels,
  uint8_t pathlevel_reverse, uint8_t source_level, uint8_t join_level, uint8_t join_multiplicity,
  uint8_t rel_id, uint8_t *sel, uint8_t *width, uint8_t ws, uint8_t multicast_overhead)
{                                     // estimate cost to send data values to join node, and join node result
  return (is_base ?
      10*estimate_forwardmsgcost(1, 1, source_level, NULL, 0, TUPLE_OVERHEAD+2*width[rel_id]) :
      10*estimate_forwardmsgcost(0, 0, path_len, path_levels, pathlevel_reverse,
        TUPLE_OVERHEAD+2*width[rel_id]+multicast_overhead) + ((join_multiplicity == 0) ? 0 :
      (((uint32_t)join_prob(sel[REL_J], ws, join_multiplicity))*
      estimate_forwardmsgcost(1, 1, join_level, NULL, 0, TUPLE_OVERHEAD+
        ((uint32_t) 100)*2*width[REL_J]*join_multiplicity*ws/
        (sel[REL_J]*(uint32_t)join_prob(sel[REL_J], ws, join_multiplicity))))
      )/10)
    /sel[rel_id];
}

uint32_t estimate_paircost(uint8_t *joinsource_levels, int joinsource_pathlen,
  uint8_t *targetjoin_levels, int targetjoin_pathlen, uint8_t is_base, uint8_t rel_id, uint8_t *sel,
  uint8_t *width, uint8_t ws)  // estimate cost of pairwise join
{
  return estimate_singlejoincost(is_base, joinsource_pathlen-1, joinsource_levels, 1,
    joinsource_levels[joinsource_pathlen-1], joinsource_levels[0], 1, rel_id, sel, width, ws, 0) +
    estimate_singlejoincost(is_base, targetjoin_pathlen-1, &targetjoin_levels[1], 0,
    targetjoin_levels[0], joinsource_levels[0], 1, 1-rel_id, sel, width, ws, 0);
}

uint32_t estimate_multicastcost(MULTICAST_NODE *n, uint8_t is_cached, uint8_t rel_id, uint8_t *sel,
  uint8_t *width, uint8_t ws, uint8_t level)
{                                              // estimate cost of multicast from source to join nodes and join results
  int i;
  uint32_t sum;

  if (n == NULL)
    return 0;

  sum = estimate_singlejoincost(n->path[n->path_len-1] == BASESTATION_ADDR, n->path_len-(level == 0),
    NULL, 0, n->node_level, n->node_level, n->multiplicity, rel_id, sel, width, ws,
    (is_cached ? 1 : 10)*(1 + n->marshal_size - ((level > 0) ? PATHVEC_OVERHEAD(n->path_len) : 0))/10);

  for (i = 0; i < n->child_count; i++)
    sum += estimate_multicastcost(n->children[i], is_cached, rel_id, sel, width, ws, level+1);

  return sum;
}


